Introduction
Sampling distributions form the cornerstone of statistical inference.
They describe the probability distribution of a sample
statistic calculated from random samples. This note explores
both exact (finite-sample) and asymptotic (large-sample) distributions
for key statistics including sample means, proportions, and related test
statistics.
Sampling Distribution
of the Sample Mean
When the population is normal, by the property of normal
distribution, the sum of the iid random variables are
exactly normally distributed. If the population is not
a normal distribution, using the Central Limit Theorem (CLT), the sum of
the iid random variables is asymptotically normally
distributed.
Exact
Distribution
For a random sample \(X_1, X_2, \ldots,
X_n\) from a normal population \(N(\mu,
\sigma^2)\), the sample mean has an exact normal
distribution:
\[
\bar{X} \to N\left(\mu, \frac{\sigma}{\sqrt{n}}\right)
\]
The standardized version is:
\[
Z = \frac{\bar{X}-\mu}{\sigma/\sqrt{n}} \to N(0, 1)
\]
Example:
set.seed(123)
n <- 10
mu <- 5
sigma <- 2
n.samples <- 10000
sample.means <- replicate(n.samples, mean(rnorm(n, mu, sigma)))
# Create theoretical curve data
x.vals <- seq(mu - 3*sigma/sqrt(n), mu + 3*sigma/sqrt(n), length.out = 100)
theory.density <- dnorm(x.vals, mean = mu, sd = sigma/sqrt(n))
theory.df <- data.frame(x = x.vals, density = theory.density)
xbar.plt <- ggplot(data.frame(mean = sample.means), aes(x = mean)) +
geom_histogram(aes(y = ..density..), bins = 50, alpha = 0.7, fill = "gray") +
geom_line(data = theory.df, aes(x = x, y = density),
color = "red", linewidth = 1) +
labs(title = "Exact Sampling Distribution of Sample Mean \nNormal Population (n = 10)",
x = "Sample Mean", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt"))
ggplotly(xbar.plt)
Asymptotic
Distribution (Central Limit Theorem)
For any population with finite mean \(\mu\) and variance \(\sigma^2\), as \(n \to \infty\):
\[
Z = \frac{\bar{X}-\mu}{\sigma/\sqrt{n}} \to_{\text{approx}} N(0, 1)
\]
Example Consider exponential population:
set.seed(123)
n.large <- 50
lambda <- 1/5 # Mean = 5
# Generate multiple samples from exponential distribution
n.samples <- 10000
exp.means <- replicate(n.samples, mean(rexp(n.large, rate = lambda)))
# Compare with normal approximation
theoretical.mean <- 1/lambda # 5
theoretical.sd <- (1/lambda)/sqrt(n.large) # 5/sqrt(50)
theory.density <- dnorm(x.vals, mean = theoretical.mean, sd = theoretical.sd)
theory.df <- data.frame(x = x.vals, density = theory.density)
# Option 1: Use only stat_function for theoretical curve (Recommended)
gg.clt <- ggplot(data.frame(mean = exp.means), aes(x = mean)) +
geom_histogram(aes(y = after_stat(density)), bins = 50, alpha = 0.7, fill = "lightgreen") +
geom_line(data = theory.df, aes(x = x, y = density),
color = "red", linewidth = 1) +
labs(title = "Asymptotic Sampling Distribution of Sample Mean \nExponential Population (n = 50)",
x = "Sample Mean", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt"))
#gg.clt
ggplotly(gg.clt)
Student’s
t-Distribution
When population variance \(\sigma^2\) is unknown and estimated by
sample variance \(S^2\):
\[
T = \frac{\bar{X}-\mu}{S/\sqrt{n}} \to t_{n-1}
\]
where \(S^2 = \frac{1}{n-1}\sum_{i=1}^n
(X_i - \bar{X})^2\)
Example:
set.seed(123)
n <- 10
mu <- 5
sigma <- 2
# Generate t-statistics
n.samples <- 10000
t.stats <- numeric(n.samples)
for(i in 1:n.samples) {
sample.data <- rnorm(n, mu, sigma)
x.bar <- mean(sample.data)
s <- sd(sample.data)
t.stats[i] <- (x.bar - mu) / (s/sqrt(n))
}
# Compare with theoretical t-distribution
x.vals <- seq(-4, 4, length.out = 200)
theoretical.t <- dt(x.vals, df = n-1)
theoretical.normal <- dnorm(x.vals)
comparison.df <- data.frame(
x = rep(x.vals, 2),
density = c(theoretical.t, theoretical.normal),
distribution = rep(c("t(9)", "N(0,1)"), each = length(x.vals))
)
t.plt <- ggplot(comparison.df, aes(x = x, y = density, color = distribution)) +
geom_line(size = 1) +
labs(title = "t-Distribution vs Normal Distribution",
x = "Value", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt")) +
scale_color_manual(values = c("red", "blue"))
ggplotly(t.plt)
Sampling Distribution
of Sample Proportion
3.1 Exact Distribution
For a binomial population with success probability \(p\), the sample proportion \(\hat{p} = X/n\) where \(X \sim Binomial(n,p)\).
The exact distribution is simply the probability mass function of a
binomial distribution with n trials and success probability \(p\):
\[
P(\hat{p} =k/n)=P(X = k)=\frac{n!}{k!(n-k)!} p^k (1−p)^{n-k}, \ \ k = 0,
1, 2, \cdots, n.
\]
Asymptotic
Distribution
By Central Limit Theorem, as \(n \to
\infty\):
\[
\hat{p} \to N\left(p, \sqrt{\frac{p(1-p)}{n}} \right)
\]
Example:
set.seed(123)
n <- 100
p <- 0.3
# Generate sample proportions
n.samples <- 10000
sample.props <- replicate(n.samples, rbinom(1, n, p)/n)
# Compare with normal approximation
theoretical.mean <- p
theoretical.sd <- sqrt(p*(1-p)/n)
x.vals <- seq(0,0.6, length=100)
theory.density <- dnorm(x.vals, mean = theoretical.mean, sd = theoretical.sd)
theory.df <- data.frame(x = x.vals, density = theory.density)
binom.plt <- ggplot(data.frame(prop = sample.props), aes(x = prop)) +
geom_histogram(aes(y = ..density..), bins = 30, alpha = 0.7, fill = "skyblue") +
geom_line(data = theory.df, aes(x = x, y = density),
color = "red", linewidth = 1) +
#stat_function(fun = dnorm,
# args = list(mean = theoretical_mean, sd = theoretical_sd),
# color = "red", size = 1) +
labs(title = "Sampling Distribution of Sample Proportion",
subtitle = "p = 0.3, n = 100",
x = "Sample Proportion", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt"))
ggplotly(binom.plt)
Chi-Square
Distribution
For \(Z_1, Z_2, \ldots, Z_k
\stackrel{iid}{\sim} N(0,1)\), using moment generating function,
we can show that
\[
Q=\sum_{i=1}^k Z_i^2 \to \chi_k^2.
\]
For sample variance from normal population:
\[
\frac{(n-1)S^2}{\sigma^2} \to \chi_{n-1}^2
\] Proof: We prove this in several steps:
We show that for \(X_1, \dots, X_n \iid
N(\mu, \sigma^2)\), with
\[
S^2 = \frac{1}{n-1} \sum_{i=1}^n (X_i - \bar{X})^2, \quad \bar{X} =
\frac{1}{n} \sum_{i=1}^n X_i,
\]
we have
\[
\frac{(n-1)S^2}{\sigma^2} \sim \chi_{n-1}^2.
\]
Step 1: Standardize and define notation
Let \(Z_i = \frac{X_i - \mu}{\sigma} \sim
N(0,1)\), i.i.d. Then
\[
\bar{Z} = \frac{1}{n} \sum_{i=1}^n Z_i = \frac{\bar{X} - \mu}{\sigma}.
\]
We can write:
\[
\sum_{i=1}^n (X_i - \bar{X})^2 = \sigma^2 \sum_{i=1}^n (Z_i -
\bar{Z})^2.
\]
So
\[
\frac{(n-1)S^2}{\sigma^2} = \frac{\sum_{i=1}^n (X_i -
\bar{X})^2}{\sigma^2} = \sum_{i=1}^n (Z_i - \bar{Z})^2.
\]
Step 2: Orthogonal transformation
Let \(\mathbf{Z} = (Z_1, \dots,
Z_n)^T\). Choose an \(n \times
n\) orthogonal matrix \(Q\)
whose first row is \(\left(
\frac{1}{\sqrt{n}}, \dots, \frac{1}{\sqrt{n}} \right)\).
Define
\[
\mathbf{Y} = Q \mathbf{Z}.
\]
Then:
- \(Y_1 = \frac{1}{\sqrt{n}} \sum_{i=1}^n
Z_i = \sqrt{n} \, \bar{Z}\).
- Since \(Q\) is orthogonal and \(\mathbf{Z} \sim N(0, I_n)\), we have \(\mathbf{Y} \sim N(0, I_n)\) as well, so
\(Y_1, \dots, Y_n\) are i.i.d. \(N(0,1)\).
Step 3: Express sum of squares in terms of \(Y_j\)
Orthogonality implies:
\[
\sum_{i=1}^n Z_i^2 = \sum_{j=1}^n Y_j^2.
\]
Also,
\[
\sum_{i=1}^n (Z_i - \bar{Z})^2 = \sum_{i=1}^n Z_i^2 - n \bar{Z}^2.
\]
But \(n \bar{Z}^2 = Y_1^2\), so
\[
\sum_{i=1}^n (Z_i - \bar{Z})^2 = \sum_{j=1}^n Y_j^2 - Y_1^2 =
\sum_{j=2}^n Y_j^2.
\]
Step 4: Distribution
Since \(Y_2, \dots, Y_n\) are
i.i.d. \(N(0,1)\), we have
\[
\sum_{j=2}^n Y_j^2 \sim \chi_{n-1}^2.
\]
Thus
\[
\frac{(n-1)S^2}{\sigma^2} = \sum_{i=1}^n (Z_i - \bar{Z})^2 =
\sum_{j=2}^n Y_j^2 \sim \chi_{n-1}^2.
\]
Step 5: Independence from \(\bar{X}\)
Since \(Y_1 = \sqrt{n} \bar{Z}\) is
independent of \(Y_2, \dots, Y_n\), it
follows that \(\bar{X}\) is independent
of \(S^2\). That is,
\[
\boxed{\frac{(n-1)S^2}{\sigma^2} \to \chi_{n-1}^2}
\]
Example: The \(\chi^2\) distribution is derived from the
standard normal distribution. We simulate standard normal random numbers
and then transform them into \(\chi^2\)
random variables based on the derivations above. A histogram will be
plotted and overlaid with the theoretical \(\chi^2\) density curve.
set.seed(123)
n <- 10
sigma <- 2
# Generate chi-square statistics
n.samples <- 10000
chisq.stats <- numeric(n.samples)
for(i in 1:n.samples) {
sample.data <- rnorm(n, 0, sigma)
chisq.stats[i] <- sum((sample.data/sigma)^2)
}
# Compare with theoretical chi-square
x.vals <- seq(0, 30, length.out = 200)
theoretical.chisq <- dchisq(x.vals, df = n)
theory.df <- data.frame(x = x.vals, density = theoretical.chisq)
chi.plt <- ggplot(data.frame(x = chisq.stats), aes(x = x)) +
geom_histogram(aes(y = ..density..), bins = 50, alpha = 0.7, fill = "steelblue") +
geom_line(data = theory.df, aes(x = x, y = density),
color = "red", linewidth = 1) +
#stat_function(fun = dchisq, args = list(df = n), color = "red", size = 1) +
labs(title = "Chi-Square Distribution",
subtitle = "Sum of squared standard normals",
x = "Value", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt"))
ggplotly(chi.plt)
F-Distribution
For two independent chi-square random variables:
\[
F = \frac{U_1/d_1}{U_2/d_2} \to F_{d_1, d_2}
\]
where \(U_1 \sim \chi^2_{d_1}\) and
\(U_2 \sim \chi^2_{d_2}\).
F distribution is used for comparing variances: \(\frac{S_1^2/\sigma_1^2}{S_2^2/\sigma_2^2} \sim
F_{n_1-1,n_2-1}\). For example, if we test
\[
H_0: \ \sigma_1 = \sigma_2 \ \ \ v.s. \ \ \ H_a: \sigma_1 \ne \sigma_2
\] The test statistic
\[
TS = \frac{S_1^2}{S_2^2} \to F_{n_1-1, n_2-1}
\]
Example: The F distribution is directly defined
based on two independent \(\chi^2\)
distributions, which are themselves derived from standard normal
distributions. Therefore, we could generate data from normal
distributions and then transform them into F random variables. To keep
the process simple, we generate data directly from \(\chi^2\) distributions.
set.seed(123)
df1 <- 10
df2 <- 15
# Generate F statistics
n.samples <- 10000
f.stats <- numeric(n.samples)
for(i in 1:n.samples) {
u1 <- rchisq(1, df1)
u2 <- rchisq(1, df2)
f.stats[i] <- (u1/df1) / (u2/df2)
}
# Compare with theoretical F-distribution
x.vals <- seq(0, 5, length.out = 200)
theoretical.f <- df(x.vals, df1, df2)
theory.df <- data.frame(x = x.vals, density = theoretical.f)
f.plt <- ggplot(data.frame(x = f.stats), aes(x = x)) +
geom_histogram(aes(y = ..density..), bins = 50, alpha = 0.7, fill = "purple3") +
geom_line(data = theory.df, aes(x = x, y = density),
color = "red", linewidth = 1) +
coord_cartesian(xlim = c(0, 5)) +
labs(title = paste("F-Distribution \n F(", df1, ",", df2, ")", sep = ""),
x = "Value", y = "Density") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 20, b = 30, l = 30, unit = "pt"))
ggplotly(f.plt)
Summary of Key
Relationships
| \(\bar{X}\) |
\(N(\mu,
\sigma^2/n)\) |
\(N(\mu,
\sigma^2/n)\) |
Normal population or large n |
| \(\frac{\bar{X}-\mu}{S/\sqrt{n}}\) |
\(t_{n-1}\) |
\(N(0,1)\) |
Normal population |
| \(\hat{p}\) |
\(Binomial(n,p)/n\) |
\(N(p,
p(1-p)/n)\) |
\(np, n(1-p) \geq
5\) |
| \(\frac{(n-1)S^2}{\sigma^2}\) |
\(\chi^2_{n-1}\) |
- |
Normal population |
| \(\frac{S_1^2/\sigma_1^2}{S_2^2/\sigma_2^2}\) |
\(F_{n_1-1,n_2-1}\) |
- |
Normal populations |
Conclusion
Understanding sampling distributions is fundamental to
statistical inference:
Exact distributions provide precise results when assumptions are
met
Asymptotic distributions offer approximations for large
samples
The choice between exact and asymptotic methods depends on sample
size, distributional assumptions, and the specific parameter being
estimated
Modern computing allows for empirical verification of these
theoretical results
These distributions form the theoretical foundation for hypothesis
testing, confidence intervals, and many other statistical
procedures.
LS0tDQp0aXRsZTogIlNhbXBsaW5nIERpc3RyaWJ1dGlvbnMiDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIldlc3QgQ2hlc3RlciBVbml2ZXJzaXR5Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICBsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICBsaWJyYXJ5KHBsb3RseSkNCn0NCg0KIyMgbGlicmFyeShsZWFwcykNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQoNClwNCg0KDQojIEludHJvZHVjdGlvbg0KDQpTYW1wbGluZyBkaXN0cmlidXRpb25zIGZvcm0gdGhlIGNvcm5lcnN0b25lIG9mIHN0YXRpc3RpY2FsIGluZmVyZW5jZS4gVGhleSBkZXNjcmliZSB0aGUgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uIG9mIGEgKipzYW1wbGUgc3RhdGlzdGljKiogY2FsY3VsYXRlZCBmcm9tIHJhbmRvbSBzYW1wbGVzLiBUaGlzIG5vdGUgZXhwbG9yZXMgYm90aCBleGFjdCAoZmluaXRlLXNhbXBsZSkgYW5kIGFzeW1wdG90aWMgKGxhcmdlLXNhbXBsZSkgZGlzdHJpYnV0aW9ucyBmb3Iga2V5IHN0YXRpc3RpY3MgaW5jbHVkaW5nIHNhbXBsZSBtZWFucywgcHJvcG9ydGlvbnMsIGFuZCByZWxhdGVkIHRlc3Qgc3RhdGlzdGljcy4NCg0KDQojIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiB0aGUgU2FtcGxlIE1lYW4NCg0KV2hlbiB0aGUgcG9wdWxhdGlvbiBpcyBub3JtYWwsIGJ5IHRoZSBwcm9wZXJ0eSBvZiBub3JtYWwgZGlzdHJpYnV0aW9uLCB0aGUgc3VtIG9mIHRoZSBpaWQgcmFuZG9tIHZhcmlhYmxlcyBhcmUgKipleGFjdGx5Kiogbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIElmIHRoZSBwb3B1bGF0aW9uIGlzIG5vdCBhIG5vcm1hbCBkaXN0cmlidXRpb24sIHVzaW5nIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gKENMVCksIHRoZSBzdW0gb2YgdGhlIGlpZCByYW5kb20gdmFyaWFibGVzIGlzICoqYXN5bXB0b3RpY2FsbHkqKiBub3JtYWxseSBkaXN0cmlidXRlZC4NCg0KDQojIyBFeGFjdCBEaXN0cmlidXRpb24NCg0KRm9yIGEgcmFuZG9tIHNhbXBsZSAkWF8xLCBYXzIsIFxsZG90cywgWF9uJCBmcm9tIGEgbm9ybWFsIHBvcHVsYXRpb24gJE4oXG11LCBcc2lnbWFeMikkLCB0aGUgc2FtcGxlIG1lYW4gaGFzIGFuIGV4YWN0IG5vcm1hbCBkaXN0cmlidXRpb246DQoNCiQkDQpcYmFye1h9IFx0byBOXGxlZnQoXG11LCAgXGZyYWN7XHNpZ21hfXtcc3FydHtufX1ccmlnaHQpDQokJA0KDQpUaGUgc3RhbmRhcmRpemVkIHZlcnNpb24gaXM6DQoNCiQkDQpaID0gXGZyYWN7XGJhcntYfS1cbXV9e1xzaWdtYS9cc3FydHtufX0gXHRvIE4oMCwgMSkNCiQkDQoNCioqRXhhbXBsZSoqOg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCm4gPC0gMTANCm11IDwtIDUNCnNpZ21hIDwtIDINCg0Kbi5zYW1wbGVzIDwtIDEwMDAwDQpzYW1wbGUubWVhbnMgPC0gcmVwbGljYXRlKG4uc2FtcGxlcywgbWVhbihybm9ybShuLCBtdSwgc2lnbWEpKSkNCg0KIyBDcmVhdGUgdGhlb3JldGljYWwgY3VydmUgZGF0YQ0KeC52YWxzIDwtIHNlcShtdSAtIDMqc2lnbWEvc3FydChuKSwgbXUgKyAzKnNpZ21hL3NxcnQobiksIGxlbmd0aC5vdXQgPSAxMDApDQp0aGVvcnkuZGVuc2l0eSA8LSBkbm9ybSh4LnZhbHMsIG1lYW4gPSBtdSwgc2QgPSBzaWdtYS9zcXJ0KG4pKQ0KdGhlb3J5LmRmIDwtIGRhdGEuZnJhbWUoeCA9IHgudmFscywgZGVuc2l0eSA9IHRoZW9yeS5kZW5zaXR5KQ0KDQp4YmFyLnBsdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShtZWFuID0gc2FtcGxlLm1lYW5zKSwgYWVzKHggPSBtZWFuKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlucyA9IDUwLCBhbHBoYSA9IDAuNywgZmlsbCA9ICJncmF5IikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHRoZW9yeS5kZiwgYWVzKHggPSB4LCB5ID0gZGVuc2l0eSksIA0KICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgbGluZXdpZHRoID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIkV4YWN0IFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBTYW1wbGUgTWVhbiBcbk5vcm1hbCBQb3B1bGF0aW9uIChuID0gMTApIiwNCiAgICAgICB4ID0gIlNhbXBsZSBNZWFuIiwgeSA9ICJEZW5zaXR5IikgKw0KICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAzNSwgciA9IDIwLCBiID0gMzAsIGwgPSAzMCwgdW5pdCA9ICJwdCIpKQ0KDQpnZ3Bsb3RseSh4YmFyLnBsdCkNCg0KYGBgDQoNCg0KIyMgQXN5bXB0b3RpYyBEaXN0cmlidXRpb24gKENlbnRyYWwgTGltaXQgVGhlb3JlbSkNCg0KRm9yIGFueSBwb3B1bGF0aW9uIHdpdGggZmluaXRlIG1lYW4gJFxtdSQgYW5kIHZhcmlhbmNlICRcc2lnbWFeMiQsIGFzICRuIFx0byBcaW5mdHkkOg0KDQoNCg0KJCQNClogPSBcZnJhY3tcYmFye1h9LVxtdX17XHNpZ21hL1xzcXJ0e259fSBcdG9fe1x0ZXh0e2FwcHJveH19IE4oMCwgMSkNCiQkDQoNCg0KKipFeGFtcGxlKiogQ29uc2lkZXIgZXhwb25lbnRpYWwgcG9wdWxhdGlvbjoNCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpuLmxhcmdlIDwtIDUwDQpsYW1iZGEgPC0gMS81ICAjIE1lYW4gPSA1DQoNCiMgR2VuZXJhdGUgbXVsdGlwbGUgc2FtcGxlcyBmcm9tIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbg0Kbi5zYW1wbGVzIDwtIDEwMDAwDQpleHAubWVhbnMgPC0gcmVwbGljYXRlKG4uc2FtcGxlcywgbWVhbihyZXhwKG4ubGFyZ2UsIHJhdGUgPSBsYW1iZGEpKSkNCg0KIyBDb21wYXJlIHdpdGggbm9ybWFsIGFwcHJveGltYXRpb24NCnRoZW9yZXRpY2FsLm1lYW4gPC0gMS9sYW1iZGEgICMgNQ0KdGhlb3JldGljYWwuc2QgPC0gKDEvbGFtYmRhKS9zcXJ0KG4ubGFyZ2UpICAjIDUvc3FydCg1MCkNCg0KdGhlb3J5LmRlbnNpdHkgPC0gZG5vcm0oeC52YWxzLCBtZWFuID0gdGhlb3JldGljYWwubWVhbiwgc2QgPSB0aGVvcmV0aWNhbC5zZCkNCnRoZW9yeS5kZiA8LSBkYXRhLmZyYW1lKHggPSB4LnZhbHMsIGRlbnNpdHkgPSB0aGVvcnkuZGVuc2l0eSkNCg0KIyBPcHRpb24gMTogVXNlIG9ubHkgc3RhdF9mdW5jdGlvbiBmb3IgdGhlb3JldGljYWwgY3VydmUgKFJlY29tbWVuZGVkKQ0KZ2cuY2x0IDwtIGdncGxvdChkYXRhLmZyYW1lKG1lYW4gPSBleHAubWVhbnMpLCBhZXMoeCA9IG1lYW4pKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksIGJpbnMgPSA1MCwgYWxwaGEgPSAwLjcsIGZpbGwgPSAibGlnaHRncmVlbiIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSB0aGVvcnkuZGYsIGFlcyh4ID0geCwgeSA9IGRlbnNpdHkpLCANCiAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJBc3ltcHRvdGljIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBTYW1wbGUgTWVhbiBcbkV4cG9uZW50aWFsIFBvcHVsYXRpb24gKG4gPSA1MCkiLA0KICAgICAgIHggPSAiU2FtcGxlIE1lYW4iLCB5ID0gIkRlbnNpdHkiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMzUsIHIgPSAyMCwgYiA9IDMwLCBsID0gMzAsIHVuaXQgPSAicHQiKSkNCiNnZy5jbHQNCmdncGxvdGx5KGdnLmNsdCkNCmBgYA0KDQoNCg0KDQoNCg0KIyBTdHVkZW50J3MgdC1EaXN0cmlidXRpb24NCg0KV2hlbiBwb3B1bGF0aW9uIHZhcmlhbmNlICRcc2lnbWFeMiQgaXMgdW5rbm93biBhbmQgZXN0aW1hdGVkIGJ5IHNhbXBsZSB2YXJpYW5jZSAkU14yJDoNCg0KJCQNClQgPSBcZnJhY3tcYmFye1h9LVxtdX17Uy9cc3FydHtufX0gXHRvICB0X3tuLTF9DQokJA0KDQp3aGVyZSAkU14yID0gXGZyYWN7MX17bi0xfVxzdW1fe2k9MX1ebiAoWF9pIC0gXGJhcntYfSleMiQNCg0KDQoNCioqRXhhbXBsZSoqOg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCm4gPC0gMTANCm11IDwtIDUNCnNpZ21hIDwtIDINCg0KIyBHZW5lcmF0ZSB0LXN0YXRpc3RpY3MNCm4uc2FtcGxlcyA8LSAxMDAwMA0KdC5zdGF0cyA8LSBudW1lcmljKG4uc2FtcGxlcykNCg0KZm9yKGkgaW4gMTpuLnNhbXBsZXMpIHsNCiAgc2FtcGxlLmRhdGEgPC0gcm5vcm0obiwgbXUsIHNpZ21hKQ0KICB4LmJhciA8LSBtZWFuKHNhbXBsZS5kYXRhKQ0KICBzIDwtIHNkKHNhbXBsZS5kYXRhKQ0KICB0LnN0YXRzW2ldIDwtICh4LmJhciAtIG11KSAvIChzL3NxcnQobikpDQp9DQoNCiMgQ29tcGFyZSB3aXRoIHRoZW9yZXRpY2FsIHQtZGlzdHJpYnV0aW9uDQp4LnZhbHMgPC0gc2VxKC00LCA0LCBsZW5ndGgub3V0ID0gMjAwKQ0KdGhlb3JldGljYWwudCA8LSBkdCh4LnZhbHMsIGRmID0gbi0xKQ0KdGhlb3JldGljYWwubm9ybWFsIDwtIGRub3JtKHgudmFscykNCg0KY29tcGFyaXNvbi5kZiA8LSBkYXRhLmZyYW1lKA0KICB4ID0gcmVwKHgudmFscywgMiksDQogIGRlbnNpdHkgPSBjKHRoZW9yZXRpY2FsLnQsIHRoZW9yZXRpY2FsLm5vcm1hbCksDQogIGRpc3RyaWJ1dGlvbiA9IHJlcChjKCJ0KDkpIiwgIk4oMCwxKSIpLCBlYWNoID0gbGVuZ3RoKHgudmFscykpDQopDQoNCnQucGx0IDwtIGdncGxvdChjb21wYXJpc29uLmRmLCBhZXMoeCA9IHgsIHkgPSBkZW5zaXR5LCBjb2xvciA9IGRpc3RyaWJ1dGlvbikpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAidC1EaXN0cmlidXRpb24gdnMgTm9ybWFsIERpc3RyaWJ1dGlvbiIsDQogICAgICAgeCA9ICJWYWx1ZSIsIHkgPSAiRGVuc2l0eSIpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDM1LCByID0gMjAsIGIgPSAzMCwgbCA9IDMwLCB1bml0ID0gInB0IikpICsNCiAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAiYmx1ZSIpKQ0KZ2dwbG90bHkodC5wbHQpDQpgYGANCg0KDQoNCiMgU2FtcGxpbmcgRGlzdHJpYnV0aW9uIG9mIFNhbXBsZSBQcm9wb3J0aW9uDQoNCjMuMSBFeGFjdCBEaXN0cmlidXRpb24NCg0KRm9yIGEgYmlub21pYWwgcG9wdWxhdGlvbiB3aXRoIHN1Y2Nlc3MgcHJvYmFiaWxpdHkgJHAkLCB0aGUgc2FtcGxlIHByb3BvcnRpb24gJFxoYXR7cH0gPSBYL24kIHdoZXJlICRYIFxzaW0gQmlub21pYWwobixwKSQuDQoNClRoZSBleGFjdCBkaXN0cmlidXRpb24gaXMgc2ltcGx5IHRoZSBwcm9iYWJpbGl0eSBtYXNzIGZ1bmN0aW9uIG9mIGEgYmlub21pYWwgZGlzdHJpYnV0aW9uIHdpdGggbiB0cmlhbHMgYW5kIHN1Y2Nlc3MgcHJvYmFiaWxpdHkgJHAkOg0KDQokJA0KUChcaGF0e3B9ID1rL24pPVAoWCA9IGspPVxmcmFje24hfXtrIShuLWspIX0gcF5rICgx4oiScClee24ta30sIFwgXCBrID0gMCwgMSwgMiwgXGNkb3RzLCBuLg0KJCQgDQoNCg0KIyMgQXN5bXB0b3RpYyBEaXN0cmlidXRpb24NCg0KQnkgQ2VudHJhbCBMaW1pdCBUaGVvcmVtLCBhcyAkbiBcdG8gXGluZnR5JDoNCg0KJCQNClxoYXR7cH0gXHRvIE5cbGVmdChwLCBcc3FydHtcZnJhY3twKDEtcCl9e259fSBccmlnaHQpDQokJA0KDQoqKkV4YW1wbGUqKjoNCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpuIDwtIDEwMA0KcCA8LSAwLjMNCg0KIyBHZW5lcmF0ZSBzYW1wbGUgcHJvcG9ydGlvbnMNCm4uc2FtcGxlcyA8LSAxMDAwMA0Kc2FtcGxlLnByb3BzIDwtIHJlcGxpY2F0ZShuLnNhbXBsZXMsIHJiaW5vbSgxLCBuLCBwKS9uKQ0KDQojIENvbXBhcmUgd2l0aCBub3JtYWwgYXBwcm94aW1hdGlvbg0KdGhlb3JldGljYWwubWVhbiA8LSBwDQp0aGVvcmV0aWNhbC5zZCA8LSBzcXJ0KHAqKDEtcCkvbikNCg0KeC52YWxzIDwtIHNlcSgwLDAuNiwgbGVuZ3RoPTEwMCkNCnRoZW9yeS5kZW5zaXR5IDwtIGRub3JtKHgudmFscywgbWVhbiA9IHRoZW9yZXRpY2FsLm1lYW4sIHNkID0gdGhlb3JldGljYWwuc2QpDQp0aGVvcnkuZGYgPC0gZGF0YS5mcmFtZSh4ID0geC52YWxzLCBkZW5zaXR5ID0gdGhlb3J5LmRlbnNpdHkpDQoNCmJpbm9tLnBsdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShwcm9wID0gc2FtcGxlLnByb3BzKSwgYWVzKHggPSBwcm9wKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlucyA9IDMwLCBhbHBoYSA9IDAuNywgZmlsbCA9ICJza3libHVlIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHRoZW9yeS5kZiwgYWVzKHggPSB4LCB5ID0gZGVuc2l0eSksIA0KICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgbGluZXdpZHRoID0gMSkgKw0KICAjc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgDQogICMgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1lYW4gPSB0aGVvcmV0aWNhbF9tZWFuLCBzZCA9IHRoZW9yZXRpY2FsX3NkKSwNCiAgIyAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJTYW1wbGluZyBEaXN0cmlidXRpb24gb2YgU2FtcGxlIFByb3BvcnRpb24iLA0KICAgICAgIHN1YnRpdGxlID0gInAgPSAwLjMsIG4gPSAxMDAiLA0KICAgICAgIHggPSAiU2FtcGxlIFByb3BvcnRpb24iLCB5ID0gIkRlbnNpdHkiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMzUsIHIgPSAyMCwgYiA9IDMwLCBsID0gMzAsIHVuaXQgPSAicHQiKSkNCmdncGxvdGx5KGJpbm9tLnBsdCkNCmBgYA0KDQoNCiMgQ2hpLVNxdWFyZSBEaXN0cmlidXRpb24NCg0KRm9yICRaXzEsIFpfMiwgXGxkb3RzLCBaX2sgXHN0YWNrcmVse2lpZH17XHNpbX0gTigwLDEpJCwgdXNpbmcgbW9tZW50IGdlbmVyYXRpbmcgZnVuY3Rpb24sIHdlIGNhbiBzaG93IHRoYXQNCg0KJCQNClE9XHN1bV97aT0xfV5rIFpfaV4yIFx0byBcY2hpX2teMi4NCiQkDQogDQoNCkZvciBzYW1wbGUgdmFyaWFuY2UgZnJvbSBub3JtYWwgcG9wdWxhdGlvbjoNCg0KJCQNClxmcmFjeyhuLTEpU14yfXtcc2lnbWFeMn0gXHRvIFxjaGlfe24tMX1eMg0KJCQNCioqUHJvb2YqKjogV2UgcHJvdmUgdGhpcyBpbiBzZXZlcmFsIHN0ZXBzOg0KDQpXZSBzaG93IHRoYXQgZm9yICRYXzEsIFxkb3RzLCBYX24gXGlpZCBOKFxtdSwgXHNpZ21hXjIpJCwgd2l0aA0KDQokJA0KU14yID0gXGZyYWN7MX17bi0xfSBcc3VtX3tpPTF9Xm4gKFhfaSAtIFxiYXJ7WH0pXjIsIFxxdWFkIFxiYXJ7WH0gPSBcZnJhY3sxfXtufSBcc3VtX3tpPTF9Xm4gWF9pLA0KJCQNCg0Kd2UgaGF2ZQ0KDQokJA0KXGZyYWN7KG4tMSlTXjJ9e1xzaWdtYV4yfSBcc2ltIFxjaGlfe24tMX1eMi4NCiQkDQoNCioqU3RlcCAxOiBTdGFuZGFyZGl6ZSBhbmQgZGVmaW5lIG5vdGF0aW9uKioNCg0KTGV0ICRaX2kgPSBcZnJhY3tYX2kgLSBcbXV9e1xzaWdtYX0gXHNpbSBOKDAsMSkkLCBpLmkuZC4gVGhlbg0KDQokJA0KXGJhcntafSA9IFxmcmFjezF9e259IFxzdW1fe2k9MX1ebiBaX2kgPSBcZnJhY3tcYmFye1h9IC0gXG11fXtcc2lnbWF9Lg0KJCQNCg0KV2UgY2FuIHdyaXRlOg0KDQokJA0KXHN1bV97aT0xfV5uIChYX2kgLSBcYmFye1h9KV4yID0gXHNpZ21hXjIgXHN1bV97aT0xfV5uIChaX2kgLSBcYmFye1p9KV4yLg0KJCQNCg0KU28NCg0KJCQNClxmcmFjeyhuLTEpU14yfXtcc2lnbWFeMn0gPSBcZnJhY3tcc3VtX3tpPTF9Xm4gKFhfaSAtIFxiYXJ7WH0pXjJ9e1xzaWdtYV4yfSA9IFxzdW1fe2k9MX1ebiAoWl9pIC0gXGJhcntafSleMi4NCiQkDQoNCioqU3RlcCAyOiBPcnRob2dvbmFsIHRyYW5zZm9ybWF0aW9uKioNCg0KTGV0IFwoIFxtYXRoYmZ7Wn0gPSAoWl8xLCBcZG90cywgWl9uKV5UIFwpLiBDaG9vc2UgYW4gXCggbiBcdGltZXMgbiBcKSBvcnRob2dvbmFsIG1hdHJpeCBcKCBRIFwpIHdob3NlIGZpcnN0IHJvdyBpcyBcKCBcbGVmdCggXGZyYWN7MX17XHNxcnR7bn19LCBcZG90cywgXGZyYWN7MX17XHNxcnR7bn19IFxyaWdodCkgXCkuIERlZmluZQ0KDQokJA0KXG1hdGhiZntZfSA9IFEgXG1hdGhiZntafS4NCiQkDQoNClRoZW46DQoNCiogJFlfMSA9IFxmcmFjezF9e1xzcXJ0e259fSBcc3VtX3tpPTF9Xm4gWl9pID0gXHNxcnR7bn0gXCwgXGJhcntafSQuDQoqIFNpbmNlICRRJCBpcyBvcnRob2dvbmFsIGFuZCAkXG1hdGhiZntafSBcc2ltIE4oMCwgSV9uKSQsIHdlIGhhdmUgJFxtYXRoYmZ7WX0gXHNpbSBOKDAsIElfbikkIGFzIHdlbGwsIHNvICRZXzEsIFxkb3RzLCBZX24kIGFyZSBpLmkuZC5cICROKDAsMSkkLg0KDQoNCioqU3RlcCAzOiBFeHByZXNzIHN1bSBvZiBzcXVhcmVzIGluIHRlcm1zIG9mIFwoIFlfaiBcKSoqDQoNCk9ydGhvZ29uYWxpdHkgaW1wbGllczoNCg0KJCQNClxzdW1fe2k9MX1ebiBaX2leMiA9IFxzdW1fe2o9MX1ebiBZX2peMi4NCiQkDQoNCkFsc28sDQoNCiQkDQpcc3VtX3tpPTF9Xm4gKFpfaSAtIFxiYXJ7Wn0pXjIgPSBcc3VtX3tpPTF9Xm4gWl9pXjIgLSBuIFxiYXJ7Wn1eMi4NCiQkDQoNCkJ1dCAkbiBcYmFye1p9XjIgPSBZXzFeMiQsIHNvDQoNCiQkDQpcc3VtX3tpPTF9Xm4gKFpfaSAtIFxiYXJ7Wn0pXjIgPSBcc3VtX3tqPTF9Xm4gWV9qXjIgLSBZXzFeMiA9IFxzdW1fe2o9Mn1ebiBZX2peMi4NCiQkDQoNCioqU3RlcCA0OiBEaXN0cmlidXRpb24qKg0KDQpTaW5jZSAkWV8yLCBcZG90cywgWV9uJCBhcmUgaS5pLmQuXCAkTigwLDEpJCwgd2UgaGF2ZQ0KDQokJA0KXHN1bV97aj0yfV5uIFlfal4yIFxzaW0gXGNoaV97bi0xfV4yLg0KJCQNCg0KVGh1cw0KDQokJA0KXGZyYWN7KG4tMSlTXjJ9e1xzaWdtYV4yfSA9IFxzdW1fe2k9MX1ebiAoWl9pIC0gXGJhcntafSleMiA9IFxzdW1fe2o9Mn1ebiBZX2peMiBcc2ltIFxjaGlfe24tMX1eMi4NCiQkDQoNCioqU3RlcCA1OiBJbmRlcGVuZGVuY2UgZnJvbSBcKCBcYmFye1h9IFwpKioNCg0KU2luY2UgJFlfMSA9IFxzcXJ0e259IFxiYXJ7Wn0kIGlzIGluZGVwZW5kZW50IG9mICRZXzIsIFxkb3RzLCBZX24kLCBpdCBmb2xsb3dzIHRoYXQgJFxiYXJ7WH0kIGlzIGluZGVwZW5kZW50IG9mICRTXjIkLiBUaGF0IGlzLA0KDQokJA0KXGJveGVke1xmcmFjeyhuLTEpU14yfXtcc2lnbWFeMn0gXHRvIFxjaGlfe24tMX1eMn0NCiQkDQoNCioqRXhhbXBsZSoqOiBUaGUgJFxjaGleMiQgZGlzdHJpYnV0aW9uIGlzIGRlcml2ZWQgZnJvbSB0aGUgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gV2Ugc2ltdWxhdGUgc3RhbmRhcmQgbm9ybWFsIHJhbmRvbSBudW1iZXJzIGFuZCB0aGVuIHRyYW5zZm9ybSB0aGVtIGludG8gJFxjaGleMiQgcmFuZG9tIHZhcmlhYmxlcyBiYXNlZCBvbiB0aGUgZGVyaXZhdGlvbnMgYWJvdmUuIEEgaGlzdG9ncmFtIHdpbGwgYmUgcGxvdHRlZCBhbmQgb3ZlcmxhaWQgd2l0aCB0aGUgdGhlb3JldGljYWwgJFxjaGleMiQgZGVuc2l0eSBjdXJ2ZS4NCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpuIDwtIDEwDQpzaWdtYSA8LSAyDQoNCiMgR2VuZXJhdGUgY2hpLXNxdWFyZSBzdGF0aXN0aWNzDQpuLnNhbXBsZXMgPC0gMTAwMDANCmNoaXNxLnN0YXRzIDwtIG51bWVyaWMobi5zYW1wbGVzKQ0KDQpmb3IoaSBpbiAxOm4uc2FtcGxlcykgew0KICBzYW1wbGUuZGF0YSA8LSBybm9ybShuLCAwLCBzaWdtYSkNCiAgY2hpc3Euc3RhdHNbaV0gPC0gc3VtKChzYW1wbGUuZGF0YS9zaWdtYSleMikNCn0NCg0KIyBDb21wYXJlIHdpdGggdGhlb3JldGljYWwgY2hpLXNxdWFyZQ0KeC52YWxzIDwtIHNlcSgwLCAzMCwgbGVuZ3RoLm91dCA9IDIwMCkNCnRoZW9yZXRpY2FsLmNoaXNxIDwtIGRjaGlzcSh4LnZhbHMsIGRmID0gbikNCnRoZW9yeS5kZiA8LSBkYXRhLmZyYW1lKHggPSB4LnZhbHMsIGRlbnNpdHkgPSB0aGVvcmV0aWNhbC5jaGlzcSkNCg0KY2hpLnBsdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZSh4ID0gY2hpc3Euc3RhdHMpLCBhZXMoeCA9IHgpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBiaW5zID0gNTAsIGFscGhhID0gMC43LCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSB0aGVvcnkuZGYsIGFlcyh4ID0geCwgeSA9IGRlbnNpdHkpLCANCiAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDEpICsNCiAgI3N0YXRfZnVuY3Rpb24oZnVuID0gZGNoaXNxLCBhcmdzID0gbGlzdChkZiA9IG4pLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIkNoaS1TcXVhcmUgRGlzdHJpYnV0aW9uIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJTdW0gb2Ygc3F1YXJlZCBzdGFuZGFyZCBub3JtYWxzIiwNCiAgICAgICB4ID0gIlZhbHVlIiwgeSA9ICJEZW5zaXR5IikgKw0KICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAzNSwgciA9IDIwLCBiID0gMzAsIGwgPSAzMCwgdW5pdCA9ICJwdCIpKQ0KZ2dwbG90bHkoY2hpLnBsdCkNCmBgYA0KDQojIEYtRGlzdHJpYnV0aW9uDQoNCkZvciB0d28gaW5kZXBlbmRlbnQgY2hpLXNxdWFyZSByYW5kb20gdmFyaWFibGVzOg0KDQokJA0KRiA9IFxmcmFje1VfMS9kXzF9e1VfMi9kXzJ9IFx0byBGX3tkXzEsIGRfMn0NCiQkDQogDQp3aGVyZSAkVV8xIFxzaW0gXGNoaV4yX3tkXzF9JCBhbmQgJFVfMiBcc2ltIFxjaGleMl97ZF8yfSQuDQoNCg0KDQpGIGRpc3RyaWJ1dGlvbiBpcyB1c2VkIGZvciBjb21wYXJpbmcgdmFyaWFuY2VzOiAkXGZyYWN7U18xXjIvXHNpZ21hXzFeMn17U18yXjIvXHNpZ21hXzJeMn0gXHNpbSBGX3tuXzEtMSxuXzItMX0kLiBGb3IgZXhhbXBsZSwgaWYgd2UgdGVzdA0KDQokJA0KSF8wOiBcIFxzaWdtYV8xID0gXHNpZ21hXzIgXCBcIFwgdi5zLiBcIFwgXCBIX2E6ICBcc2lnbWFfMSBcbmUgXHNpZ21hXzINCiQkDQpUaGUgdGVzdCBzdGF0aXN0aWMNCg0KJCQNClRTID0gXGZyYWN7U18xXjJ9e1NfMl4yfSBcdG8gRl97bl8xLTEsIG5fMi0xfQ0KJCQNCg0KDQoqKkV4YW1wbGUqKjogVGhlIEYgZGlzdHJpYnV0aW9uIGlzIGRpcmVjdGx5IGRlZmluZWQgYmFzZWQgb24gdHdvIGluZGVwZW5kZW50ICRcY2hpXjIkIGRpc3RyaWJ1dGlvbnMsIHdoaWNoIGFyZSB0aGVtc2VsdmVzIGRlcml2ZWQgZnJvbSBzdGFuZGFyZCBub3JtYWwgZGlzdHJpYnV0aW9ucy4gVGhlcmVmb3JlLCB3ZSBjb3VsZCBnZW5lcmF0ZSBkYXRhIGZyb20gbm9ybWFsIGRpc3RyaWJ1dGlvbnMgYW5kIHRoZW4gdHJhbnNmb3JtIHRoZW0gaW50byBGIHJhbmRvbSB2YXJpYWJsZXMuIFRvIGtlZXAgdGhlIHByb2Nlc3Mgc2ltcGxlLCB3ZSBnZW5lcmF0ZSBkYXRhIGRpcmVjdGx5IGZyb20gJFxjaGleMiQgZGlzdHJpYnV0aW9ucy4NCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpkZjEgPC0gMTANCmRmMiA8LSAxNQ0KDQojIEdlbmVyYXRlIEYgc3RhdGlzdGljcw0Kbi5zYW1wbGVzIDwtIDEwMDAwDQpmLnN0YXRzIDwtIG51bWVyaWMobi5zYW1wbGVzKQ0KDQpmb3IoaSBpbiAxOm4uc2FtcGxlcykgew0KICB1MSA8LSByY2hpc3EoMSwgZGYxKQ0KICB1MiA8LSByY2hpc3EoMSwgZGYyKQ0KICBmLnN0YXRzW2ldIDwtICh1MS9kZjEpIC8gKHUyL2RmMikNCn0NCg0KIyBDb21wYXJlIHdpdGggdGhlb3JldGljYWwgRi1kaXN0cmlidXRpb24NCngudmFscyA8LSBzZXEoMCwgNSwgbGVuZ3RoLm91dCA9IDIwMCkNCnRoZW9yZXRpY2FsLmYgPC0gZGYoeC52YWxzLCBkZjEsIGRmMikNCnRoZW9yeS5kZiA8LSBkYXRhLmZyYW1lKHggPSB4LnZhbHMsIGRlbnNpdHkgPSB0aGVvcmV0aWNhbC5mKQ0KDQoNCg0KDQpmLnBsdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZSh4ID0gZi5zdGF0cyksIGFlcyh4ID0geCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIGJpbnMgPSA1MCwgYWxwaGEgPSAwLjcsIGZpbGwgPSAicHVycGxlMyIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSB0aGVvcnkuZGYsIGFlcyh4ID0geCwgeSA9IGRlbnNpdHkpLCANCiAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDEpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDUpKSArDQogIGxhYnModGl0bGUgPSBwYXN0ZSgiRi1EaXN0cmlidXRpb24gXG4gRigiLCBkZjEsICIsIiwgZGYyLCAiKSIsIHNlcCA9ICIiKSwNCiAgICAgICB4ID0gIlZhbHVlIiwgeSA9ICJEZW5zaXR5IikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDM1LCByID0gMjAsIGIgPSAzMCwgbCA9IDMwLCB1bml0ID0gInB0IikpDQpnZ3Bsb3RseShmLnBsdCkNCmBgYA0KDQoNCg0KIyBTdW1tYXJ5IG9mIEtleSBSZWxhdGlvbnNoaXBzDQoNCnxTdGF0aXN0aWMJfCBFeGFjdCBEaXN0cmlidXRpb24gfAlBc3ltcHRvdGljIERpc3RyaWJ1dGlvbiB8CUNvbmRpdGlvbnMgfA0KfDotLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS18DQp8ICRcYmFye1h9JAl8ICROKFxtdSwgXHNpZ21hXjIvbikkfCAJJE4oXG11LCBcc2lnbWFeMi9uKSR8IAlOb3JtYWwgcG9wdWxhdGlvbiBvciBsYXJnZSBufCANCnwgJFxmcmFje1xiYXJ7WH0tXG11fXtTL1xzcXJ0e259fSR8IAkkdF97bi0xfSQJfCAkTigwLDEpJHwgCU5vcm1hbCBwb3B1bGF0aW9ufCANCnwgJFxoYXR7cH0kCXwgJEJpbm9taWFsKG4scCkvbiQJfCAkTihwLCBwKDEtcCkvbikkfCAJJG5wLCBuKDEtcCkgXGdlcSA1JHwgDQp8ICRcZnJhY3sobi0xKVNeMn17XHNpZ21hXjJ9JAl8ICRcY2hpXjJfe24tMX0kIHwtCXwgTm9ybWFsIHBvcHVsYXRpb258IA0KfCAkXGZyYWN7U18xXjIvXHNpZ21hXzFeMn17U18yXjIvXHNpZ21hXzJeMn0kfCAkRl97bl8xLTEsbl8yLTF9JHwgCS0JfCBOb3JtYWwgcG9wdWxhdGlvbnN8IA0KDQoNCioqQ29uY2x1c2lvbioqDQoNCiogVW5kZXJzdGFuZGluZyBzYW1wbGluZyBkaXN0cmlidXRpb25zIGlzIGZ1bmRhbWVudGFsIHRvIHN0YXRpc3RpY2FsIGluZmVyZW5jZToNCg0KKiBFeGFjdCBkaXN0cmlidXRpb25zIHByb3ZpZGUgcHJlY2lzZSByZXN1bHRzIHdoZW4gYXNzdW1wdGlvbnMgYXJlIG1ldA0KDQoqIEFzeW1wdG90aWMgZGlzdHJpYnV0aW9ucyBvZmZlciBhcHByb3hpbWF0aW9ucyBmb3IgbGFyZ2Ugc2FtcGxlcw0KDQoqIFRoZSBjaG9pY2UgYmV0d2VlbiBleGFjdCBhbmQgYXN5bXB0b3RpYyBtZXRob2RzIGRlcGVuZHMgb24gc2FtcGxlIHNpemUsIGRpc3RyaWJ1dGlvbmFsIGFzc3VtcHRpb25zLCBhbmQgdGhlIHNwZWNpZmljIHBhcmFtZXRlciBiZWluZyBlc3RpbWF0ZWQNCg0KKiBNb2Rlcm4gY29tcHV0aW5nIGFsbG93cyBmb3IgZW1waXJpY2FsIHZlcmlmaWNhdGlvbiBvZiB0aGVzZSB0aGVvcmV0aWNhbCByZXN1bHRzDQoNCg0KVGhlc2UgZGlzdHJpYnV0aW9ucyBmb3JtIHRoZSB0aGVvcmV0aWNhbCBmb3VuZGF0aW9uIGZvciBoeXBvdGhlc2lzIHRlc3RpbmcsIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLCBhbmQgbWFueSBvdGhlciBzdGF0aXN0aWNhbCBwcm9jZWR1cmVzLg0KDQoNCg0KDQoNCg==